home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************
- * CagdDist.c - Distance computations. *
- *******************************************************************************
- * Written by Gershon Elber, May 93. *
- ******************************************************************************/
-
- #include <ctype.h>
- #include <stdio.h>
- #include <string.h>
- #include "cagd_loc.h"
-
- #define SELF_INTER_REL_EPS 100
-
- static CagdPtStruct
- *GlblSrfDistPtsList = NULL;
-
- static void CagdSrfDistFindPointsAux(CagdSrfStruct *Srf, CagdRType Epsilon,
- CagdBType SelfInter);
- static void SrfDistAddZeroPoint(CagdRType u, CagdRType v, CagdRType Epsilon);
-
- /******************************************************************************
- * Given a curve and a point, find the closest point (if MinDist) or the far *
- * location (if !MinDist) from the curve to the given point. *
- * Returned is the parameter value of the curve. *
- ******************************************************************************/
- CagdRType CagdDistCrvPoint(CagdCrvStruct *Crv, CagdPType Pt, CagdBType MinDist,
- CagdRType Epsilon)
- {
- CagdRType TMin, TMax, t,
- ExtremeDist = MinDist ? INFINITY : -INFINITY;
- CagdPtStruct *TPt,
- *Pts = CagdLclDistCrvPoint(Crv, Pt, Epsilon);
-
- /* Add the two end point of the domain. */
- CagdCrvDomain(Crv, &TMin, &TMax);
- TPt = IritMalloc(sizeof(CagdPtStruct));
- TPt -> Pt[0] = TMin;
- TPt -> Pnext = Pts;
- Pts = TPt;
- TPt = IritMalloc(sizeof(CagdPtStruct));
- TPt -> Pt[0] = TMax;
- TPt -> Pnext = Pts;
- Pts = TPt;
-
- for (TPt = Pts, t = TMin; TPt != NULL; TPt = TPt -> Pnext) {
- int i;
- CagdPType EPt;
- CagdRType
- Dist = 0.0,
- *R = CagdCrvEval(Crv, TPt -> Pt[0]);
-
- CagdCoerceToE3(EPt, &R, - 1, Crv -> PType);
-
- for (i = 0; i < 3; i++)
- Dist += SQR(EPt[i] - Pt[i]);
-
- if (MinDist) {
- if (Dist < ExtremeDist) {
- t = TPt -> Pt[0];
- ExtremeDist = Dist;
- }
- }
- else {
- if (Dist > ExtremeDist) {
- t = TPt -> Pt[0];
- ExtremeDist = Dist;
- }
- }
- }
-
- return t;
- }
-
- /******************************************************************************
- * Given a curve and a point, find the local extremum distance points on the *
- * curve to the given point. Return is a list of parametr value with local *
- * extremum. *
- * Computes the zero set of (Crv(t) - Pt) . Crv'(t). *
- ******************************************************************************/
- CagdPtStruct *CagdLclDistCrvPoint(CagdCrvStruct *Crv, CagdPType Pt,
- CagdRType Epsilon)
- {
- int i;
- CagdCrvStruct *ZCrv,
- *DCrv = CagdCrvDerive(Crv);
- CagdPType MinusPt;
- CagdPtStruct *ZeroSet;
-
- for (i = 0; i < 3; i++)
- MinusPt[i] = -Pt[i];
-
- Crv = CagdCrvCopy(Crv);
- CagdCrvTransform(Crv, MinusPt, 1.0);
-
- ZCrv = CagdCrvDotProd(Crv, DCrv);
- CagdCrvFree(Crv);
- CagdCrvFree(DCrv);
-
- ZeroSet = CagdCrvZeroSet(ZCrv, 1, Epsilon);
- CagdCrvFree(ZCrv);
-
- return ZeroSet;
- }
-
- /******************************************************************************
- * Given a curve and a line, find the closest point (if MinDist) or the far *
- * location (if !MinDist) from the curve to the given line. *
- * Returned is the parameter value of the curve. *
- ******************************************************************************/
- CagdRType CagdDistCrvLine(CagdCrvStruct *Crv, CagdLType Line,
- CagdBType MinDist, CagdRType Epsilon)
- {
- CagdRType TMin, TMax, t,
- ExtremeDist = MinDist ? INFINITY : -INFINITY;
- CagdPtStruct *TPt,
- *Pts = CagdLclDistCrvLine(Crv, Line, Epsilon);
-
- /* Add the two end point of the domain. */
- CagdCrvDomain(Crv, &TMin, &TMax);
- TPt = IritMalloc(sizeof(CagdPtStruct));
- TPt -> Pt[0] = TMin;
- TPt -> Pnext = Pts;
- Pts = TPt;
- TPt = IritMalloc(sizeof(CagdPtStruct));
- TPt -> Pt[0] = TMax;
- TPt -> Pnext = Pts;
- Pts = TPt;
-
- for (TPt = Pts, t = TMin; TPt != NULL; TPt = TPt -> Pnext) {
- CagdPType EPt;
- CagdRType
- Dist = 0.0,
- *R = CagdCrvEval(Crv, TPt -> Pt[0]);
-
- CagdCoerceToE2(EPt, &R, - 1, Crv -> PType);
-
- Dist = EPt[0] * Line[0] + EPt[1] * Line[1] + Line[2];
- Dist = ABS(Dist);
-
- if (MinDist) {
- if (Dist < ExtremeDist) {
- t = TPt -> Pt[0];
- ExtremeDist = Dist;
- }
- }
- else {
- if (Dist > ExtremeDist) {
- t = TPt -> Pt[0];
- ExtremeDist = Dist;
- }
- }
- }
-
- return t;
- }
-
- /******************************************************************************
- * Given a curve and a line, find the local extremum distance points on the *
- * curve to the given line. Return is a list of parametr value with local *
- * extremum. *
- * Let Crv be x(t), y(t). By substituting x(t) and y(t) into the line *
- * equation, we derive the distance function. Its zero set, combined with the *
- * zero set of its derivative provide the needed extrema. *
- ******************************************************************************/
- CagdPtStruct *CagdLclDistCrvLine(CagdCrvStruct *Crv, CagdLType Line,
- CagdRType Epsilon)
- {
- CagdPType Pt;
- CagdCrvStruct *TCrv1, *CrvX, *CrvY, *CrvZ, *CrvW, *DistCrv, *DerivDistCrv;
- CagdPtStruct *ZeroSet1, *ZeroSet2, *TPt;
-
- CagdCrvSplitScalar(Crv, &CrvW, &CrvX, &CrvY, &CrvZ);
- if (CrvZ)
- CagdCrvFree(CrvZ);
-
- Pt[0] = Pt[1] = Pt[2] = 0.0;
- CagdCrvTransform(CrvX, Pt, Line[0]);
- CagdCrvTransform(CrvY, Pt, Line[1]);
- TCrv1 = CagdCrvAdd(CrvX, CrvY);
- CagdCrvFree(CrvX);
- CagdCrvFree(CrvY);
- if (CrvW) {
- CagdCrvTransform(CrvW, Pt, Line[2]);
- DistCrv = CagdCrvAdd(TCrv1, CrvW);
- CagdCrvFree(CrvW);
- CagdCrvFree(TCrv1);
- }
- else {
- Pt[0] = Line[2];
- CagdCrvTransform(TCrv1, Pt, 1.0);
- DistCrv = TCrv1;
- }
-
- ZeroSet1 = CagdCrvZeroSet(DistCrv, 1, Epsilon);
-
- DerivDistCrv = CagdCrvDerive(DistCrv);
- CagdCrvFree(DistCrv);
-
- ZeroSet2 = CagdCrvZeroSet(DerivDistCrv, 1, Epsilon);
- CagdCrvFree(DerivDistCrv);
-
- if (ZeroSet1 == NULL)
- return ZeroSet2;
- else if (ZeroSet2 == NULL)
- return ZeroSet1;
- else {
- for (TPt = ZeroSet1; TPt -> Pnext != NULL; TPt = TPt -> Pnext);
-
- TPt -> Pnext = ZeroSet2;
-
- return ZeroSet1;
- }
- }
-
- /******************************************************************************
- * Given two curves, creates a scalar surface representing the distance square *
- * between them. *
- ******************************************************************************/
- CagdSrfStruct *CagdSrfDistCrvCrv(CagdCrvStruct *Crv1, CagdCrvStruct *Crv2)
- {
- CagdSrfStruct *TSrf, *DiffSrf, *DotProdSrf,
- *Srf1 = CagdPromoteCrvToSrf(Crv1, CAGD_CONST_U_DIR),
- *Srf2 = CagdPromoteCrvToSrf(Crv2, CAGD_CONST_V_DIR);
-
- if (CAGD_IS_BSPLINE_SRF(Srf1) || CAGD_IS_BSPLINE_SRF(Srf2)) {
- CagdRType UMin1, UMax1, VMin1, VMax1, UMin2, UMax2, VMin2, VMax2;
-
- if (CAGD_IS_BEZIER_SRF(Srf1)) {
- TSrf = CnvrtBezier2BsplineSrf(Srf1);
- CagdSrfFree(Srf1);
- Srf1 = TSrf;
- }
- if (CAGD_IS_BEZIER_SRF(Srf2)) {
- TSrf = CnvrtBezier2BsplineSrf(Srf2);
- CagdSrfFree(Srf2);
- Srf2 = TSrf;
- }
-
- CagdSrfDomain(Srf1, &UMin1, &UMax1, &VMin1, &VMax1);
- CagdSrfDomain(Srf2, &UMin2, &UMax2, &VMin2, &VMax2);
- BspKnotAffineTrans(Srf1 -> VKnotVector,
- Srf1 -> VLength + Srf1 -> VOrder,
- VMin2 - VMin1, (VMax2 - VMin2) / (VMax1 - VMin1));
- BspKnotAffineTrans(Srf2 -> UKnotVector,
- Srf2 -> ULength + Srf1 -> VOrder,
- UMin1 - UMin2, (UMax1 - UMin1) / (UMax2 - UMin2));
- }
-
- DiffSrf = CagdSrfSub(Srf1, Srf2);
- DotProdSrf = CagdSrfDotProd(DiffSrf, DiffSrf);
-
- CagdSrfFree(Srf1);
- CagdSrfFree(Srf2);
- CagdSrfFree(DiffSrf);
-
- return DotProdSrf;
- }
-
- /******************************************************************************
- * Given a scalar surface representing the distance square between two curves, *
- * find the zero set of the surface, if any and return it. *
- * The given surface is a non negative surface and zero set is its minima. *
- * The returned points will contail the two parameter values of the two *
- * curves that intersect in point's X & Y. *
- ******************************************************************************/
- CagdPtStruct *CagdSrfDistFindPoints(CagdSrfStruct *Srf, CagdRType Epsilon,
- CagdBType SelfInter)
- {
- GlblSrfDistPtsList = NULL;
-
- if (Srf -> GType == CAGD_SBEZIER_TYPE) {
- Srf = CnvrtBezier2BsplineSrf(Srf); /* To keep track on the domains. */
- CagdSrfDistFindPointsAux(Srf, Epsilon, SelfInter);
- CagdSrfFree(Srf);
- }
- else
- CagdSrfDistFindPointsAux(Srf, Epsilon, SelfInter);
-
- return GlblSrfDistPtsList;
- }
-
- /******************************************************************************
- * Aux. function of CagdSrfDistFindPoints - does the hard work. *
- ******************************************************************************/
- static void CagdSrfDistFindPointsAux(CagdSrfStruct *Srf, CagdRType Epsilon,
- CagdBType SelfInter)
- {
- int i, j,
- ULength = Srf -> ULength,
- VLength = Srf -> VLength;
- CagdRType
- *XPts = Srf -> Points[1];
-
- for (i = 0; i < ULength; i++) {
- for (j = 0; j < VLength; j++) {
- if (*XPts++ <= 0.0) {
- CagdRType UMin, UMax, VMin, VMax;
-
- CagdSrfDomain(Srf, &UMin, &UMax, &VMin, &VMax);
-
- if (SelfInter) {
- CagdRType
- SelfInterEps = Epsilon * SELF_INTER_REL_EPS;
-
- if (UMax - UMin < SelfInterEps &&
- VMax - VMin < SelfInterEps &&
- UMax - VMin < SelfInterEps &&
- VMax - UMin < SelfInterEps)
- return;
- }
-
- /* The surface may have a zero here. Test the domain size */
- /* to make sure it makes sense to subdivide. */
- if (UMax - UMin < Epsilon && VMax - VMin < Epsilon) {
- SrfDistAddZeroPoint((UMin + UMax) / 2.0,
- (VMin + VMax) / 2.0, Epsilon);
- }
- else {
- /* Subdivide the surface and invoke recursively. */
- CagdSrfStruct *Srf1, *Srf2;
- CagdRType t;
- CagdSrfDirType Dir;
-
- if (UMax - UMin > VMax - VMin) {
- t = (UMin + UMax) / 2.0;
- Dir = CAGD_CONST_U_DIR;
- }
- else {
- t = (VMin + VMax) / 2.0;
- Dir = CAGD_CONST_V_DIR;
- }
- Srf1 = CagdSrfSubdivAtParam(Srf, t, Dir);
- Srf2 = Srf1 -> Pnext;
- CagdSrfDistFindPointsAux(Srf1, Epsilon, SelfInter);
- CagdSrfDistFindPointsAux(Srf2, Epsilon, SelfInter);
- CagdSrfFree(Srf1);
- CagdSrfFree(Srf2);
- }
- return;
- }
- }
- }
- }
-
- /******************************************************************************
- * Aux. function of CagdSrfDistFindPoints - does the hard work. *
- ******************************************************************************/
- static void SrfDistAddZeroPoint(CagdRType u, CagdRType v, CagdRType Epsilon)
- {
- CagdPtStruct *Pt;
-
- for (Pt = GlblSrfDistPtsList; Pt != NULL; Pt = Pt -> Pnext) {
- if (ABS(Pt -> Pt[0] - u) < Epsilon * 10 &&
- ABS(Pt -> Pt[1] - v) < Epsilon * 10)
- return; /* Point is already there. */
- }
-
- Pt = IritMalloc(sizeof(CagdPtStruct));
-
- Pt -> Pt[0] = u;
- Pt -> Pt[1] = v;
- Pt -> Pnext = GlblSrfDistPtsList;
- GlblSrfDistPtsList = Pt;
- }
-